package tcp

import (
	"fisherman/common/logger"
	"fmt"
	"net"
	"sync"
	"time"
)

type DisconnFunc func(isAbnormal bool)
type KickFunc func()

// TcpClient 封装
type TcpClient struct {
	Addr              string
	Id                string
	Conn              net.Conn
	msgChan           chan BaseMsg
	onDisconn         DisconnFunc
	isAbnormalDisconn bool
	secret            string
	IsConnected       bool
}

var rpcLock sync.Mutex
var rpcCmd string
var rpcCallback func(msg BaseMsg)

// 设置密钥则数据自动加签名，否则不加
func NewClient(msgChan chan BaseMsg, onDisconn DisconnFunc, secret string) *TcpClient {
	return &TcpClient{msgChan: msgChan, onDisconn: onDisconn, secret: secret}
}

// Connect 连接到主控
func (c *TcpClient) Connect(serverAddr, clientId string) (err error) {
	conn, err := net.Dial("tcp", serverAddr)
	if err != nil {
		err = fmt.Errorf("[TcpClient]连接服务端失败: %v", err)
		return
	}

	// 设置TCP连接的KeepAlive
	if _, ok := conn.(*net.TCPConn); !ok {
		err = fmt.Errorf("[TcpClient]连接服务端失败: %v", err)
		return
	}

	c.Addr = serverAddr
	c.Id = clientId
	c.Conn = conn
	sendMsg(c.Conn, BaseMsg{"set_client_id", clientId, "all", nil}, c.secret)

	connectingChan := make(chan struct{})
	var once sync.Once

	go func() {
		defer func(conn net.Conn) {
			err := conn.Close()
			if err != nil {
			}
		}(conn) // 确保连接关闭
		//定时发送心跳
		go c.sendHartbeat()
		c.isAbnormalDisconn = false
		for {
			receMsg, err := receiveMsg(c.Conn, c.secret)
			if err != nil {
				//log.Errorf("[TcpClient]接收数据错误: %v", err)
				c.isAbnormalDisconn = true
				break
			}
			if receMsg.Cmd == Cmd_Error {
				log.Error(string(receMsg.Data))
			} else if receMsg.Cmd == Cmd_OnSomeoneConnect && receMsg.FromId == clientId {
				c.IsConnected = true
				once.Do(func() {
					close(connectingChan)
				})
			} else if receMsg.Cmd == Cmd_OnSomeoneDisconnect {
				log.Infof("[TcpClient]有客户端断开：%s", receMsg.FromId)
			} else if receMsg.Cmd == rpcCmd && rpcCallback != nil {
				rpcCallback(receMsg)
				rpcCmd = ""
				rpcCallback = nil
			}
			//所有事件发出去给上层
			if c.msgChan != nil {
				c.msgChan <- receMsg
			}
		}
		if c.IsConnected {
			c.IsConnected = false
			log.Info("[TcpClient]已断开")
			if c.onDisconn != nil {
				c.onDisconn(c.isAbnormalDisconn)
			}
		}
	}()

	select {
	case <-connectingChan:
	case <-time.After(time.Second * 5):
		once.Do(func() {
			err = fmt.Errorf("[TcpClient]连接超时")
			close(connectingChan)
		})
	}

	return
}

func (c *TcpClient) sendHartbeat() {
	for {
		//服务端15秒收不到判为断开，客户端10秒发一次
		time.Sleep(10 * time.Second)
		if c.IsConnected {
			c.SendData(BaseMsg{"heartbeat", "", "", nil})
		} else {
			break
		}
	}
}

func (c *TcpClient) SendData(msg BaseMsg) {
	if !c.IsConnected {
		return
	}
	sendMsg(c.Conn, msg, c.secret)
}

func (c *TcpClient) RPC(data BaseMsg, timeout time.Duration) (result BaseMsg) {
	if !c.IsConnected {
		return
	}

	if timeout == 0 {
		timeout = time.Second * 5
	}

	rpcLock.Lock()
	defer rpcLock.Unlock()

	done := make(chan struct{})
	var once sync.Once

	//注册回调
	rpcCmd = data.Cmd
	rpcCallback = func(msg BaseMsg) {
		once.Do(func() {
			result = msg
			close(done)
			rpcCmd = ""
			rpcCallback = nil
		})
	}

	// 发送数据
	c.SendData(data)

	select {
	case <-done:
	case <-time.After(timeout):
		once.Do(func() {
			log.Infof("%s RPC超时：%s", c.Id, data.Cmd)
			close(done)
			rpcCmd = ""
			rpcCallback = nil
		})
	}

	return
}

func (c *TcpClient) Disconnect() {
	if c.Conn != nil {
		err := c.Conn.Close()
		if err != nil {
			return
		}
		log.Info("[TcpClient]已关闭")
	}
}
